package com.quectel.core.module.household.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.quectel.constant.core.grid.GridConstant;
import com.quectel.constant.global.SqlConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.constants.RedisCacheConstants;
import com.quectel.core.module.grid.dto.GridBindingDto;
import com.quectel.core.module.grid.dto.GridDto;
import com.quectel.core.module.grid.service.GridBindingService;
import com.quectel.core.module.grid.service.GridService;
import com.quectel.core.module.household.dao.HouseholdRoomDao;
import com.quectel.core.module.household.dto.HouseholdDto;
import com.quectel.core.module.household.dto.HouseholdRoomDto;
import com.quectel.core.module.household.dto.custom.CohabitantDto;
import com.quectel.core.module.household.entity.HouseholdEntity;
import com.quectel.core.module.household.entity.HouseholdRoomEntity;
import com.quectel.core.module.household.service.HouseholdRoomService;
import com.quectel.core.module.household.service.HouseholdService;
import com.quectel.core.module.village.dto.VillageRoomDto;
import com.quectel.core.module.village.service.VillageRoomService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.kit.CacheKit;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mybatis.MyBatisPlusUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 * @date 2021-11-02 13:12:15
 */
@DubboService
public class HouseholdRoomServiceImpl implements HouseholdRoomService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HouseholdRoomServiceImpl.class);

    private static final String HOUSEHOLD_ROOM_CACHE_BY_ID = RedisCacheConstants.PROJECT_NAME + "HOUSEHOLD_ROOM_CACHE_BY_ID:";

    @Autowired
    private HouseholdRoomDao householdRoomDao;
    @Autowired
    private VillageRoomService villageRoomService;
    @Autowired
    private HouseholdService householdService;
    @Autowired
    private GridService gridService;
    @Autowired
    private GridBindingService gridBindingService;

    @Override
    public List<CohabitantDto> queryCohabitant(Long householdId) {
        List<CohabitantDto> result = new ArrayList<>();
        HouseholdDto householdDto = householdService.selectCacheById(householdId);
        if (householdDto == null) {
            return result;
        }
        List<HouseholdRoomDto> householdRoomDtos = selectByHouseholdId(householdId);
        for (HouseholdRoomDto householdRoomDto : householdRoomDtos) {
            VillageRoomDto villageRoomDto = villageRoomService.selectCacheById(householdRoomDto.getRoomId());
            if (villageRoomDto == null) {
                continue;
            }
            List<HouseholdEntity> householdEntities = householdRoomDao.selectCohabitantList(villageRoomDto.getId());
            if (CollectionUtils.isNotEmpty(householdEntities)) {
                String place = villageRoomDto.getBuildingName() + villageRoomDto.getName();

                List<CohabitantDto> cohabitantDtos = CopyUtils.copyList(householdEntities, CohabitantDto.class);
                for (CohabitantDto cohabitantDto : cohabitantDtos) {
                    if (cohabitantDto.getId().equals(householdId)) {
                        // 本人跳过
                        continue;
                    }

                    cohabitantDto.setPlace(place);

                    boolean b = result.stream().anyMatch(o -> o.getId().equals(cohabitantDto.getId()));
                    if (Boolean.TRUE.equals(b)) {
                        // 存在该住户
                        for (CohabitantDto dto : result) {
                            if (dto.getId().equals(cohabitantDto.getId())) {
                                dto.setPlace(dto.getPlace() + "," + cohabitantDto.getPlace());
                                break;
                            }
                        }

                    } else {
                        result.add(cohabitantDto);
                    }
                }
            }
        }
        return result;
    }

    @Override
    public void deleteByHouseholdIdAndRoomId(Long roomId, Long householdId) {
        householdRoomDao.delete(new LambdaQueryWrapper<HouseholdRoomEntity>().eq(HouseholdRoomEntity::getRoomId, roomId)
                .eq(HouseholdRoomEntity::getHouseholdId, householdId));
    }


    @Override
    public List<HouseholdRoomDto> selectByRoomId(Long roomId) {
        List<HouseholdRoomEntity> entityList = householdRoomDao.selectList(
                new LambdaQueryWrapper<HouseholdRoomEntity>()
                        .eq(HouseholdRoomEntity::getRoomId, roomId)
        );

        return CopyUtils.copyList(entityList, HouseholdRoomDto.class).stream().map(v ->
        {
            if (v.getHouseholdId() != null) {
                HouseholdDto householdDto = householdService.selectCacheById(v.getHouseholdId());
                v.setHouseholdDto(householdDto);
            }
            return v;
        }).collect(Collectors.toList());
    }
    @Override
    public List<HouseholdRoomDto> selectByRoomIdAndIdentityTypes(Long roomId, List<Byte> identityTypes) {
        LambdaQueryWrapper<HouseholdRoomEntity> queryWrapper = new LambdaQueryWrapper<HouseholdRoomEntity>()
                .eq(HouseholdRoomEntity::getRoomId, roomId)
                .in(HouseholdRoomEntity::getIdentityCategory, identityTypes);
        if (CollectionUtils.isNotEmpty(identityTypes)) {
            queryWrapper.in(HouseholdRoomEntity::getIdentityCategory, identityTypes);
        }
        List<HouseholdRoomEntity> entityList = householdRoomDao.selectList(queryWrapper);

        return CopyUtils.copyList(entityList, HouseholdRoomDto.class).stream().map(v ->
        {
            if (v.getHouseholdId() != null) {
                HouseholdDto householdDto = householdService.selectCacheById(v.getHouseholdId());
                v.setHouseholdDto(householdDto);
            }
            return v;
        }).collect(Collectors.toList());
    }

    @Override
    public void deleteByHouseholdId(Long householdId) {
        householdRoomDao.delete(new LambdaQueryWrapper<HouseholdRoomEntity>()
                .eq(HouseholdRoomEntity::getHouseholdId, householdId));
    }

    @Override
    public HouseholdRoomDto selectByHouseholdIdAndRoomId(Long householdId, Long roomId) {
        HouseholdRoomEntity entity = householdRoomDao.selectOne(
                new LambdaQueryWrapper<HouseholdRoomEntity>()
                        .eq(HouseholdRoomEntity::getHouseholdId, householdId)
                        .eq(HouseholdRoomEntity::getRoomId, roomId)
                        .last(SqlConstants.MYSQL_LIMIT_ONE)
        );
        return CopyUtils.copyObj(entity, HouseholdRoomDto.class);
    }

    @Override
    public List<HouseholdRoomDto> selectByHouseholdId(Long householdId) {
        List<HouseholdRoomEntity> entityList = householdRoomDao.selectList(
                new LambdaQueryWrapper<HouseholdRoomEntity>()
                        .eq(HouseholdRoomEntity::getHouseholdId, householdId)
        );

        return CopyUtils.copyList(entityList, HouseholdRoomDto.class).stream().map(v ->
        {
            if (v.getRoomId() != null) {
                VillageRoomDto villageRoomDto = villageRoomService.selectById(v.getRoomId());
                v.setVillageRoomDto(villageRoomDto);
                if (villageRoomDto != null) {
                    GridBindingDto gridBinding = gridBindingService.selectOne(GridConstant.SourceType.BUILDING.getType(), villageRoomDto.getBuildingId());
                    if (gridBinding != null) {
                        Long gridId = gridBinding.getGridId();
                        GridDto grid = gridService.selectById(gridId);
                        if (grid != null) {
                            v.setGridId(gridId);
                            v.setGridName(grid.getName());
                        }
                    }
                }
            }
            return v;
        }).collect(Collectors.toList());
    }

    @Override
    public HouseholdRoomDto selectCacheById(Long id) {
        return CacheKit.cacheToRedis(
                () -> selectById(id),
                HOUSEHOLD_ROOM_CACHE_BY_ID + id,

                SystemConstants.NOT_NULL_CACHE_EXPIRE_SECONDS
        );
    }

    @Override
    public HouseholdRoomDto selectById(Long id) {
        HouseholdRoomEntity entity = householdRoomDao.selectById(id);
        return paddingField(CopyUtils.copyObj(entity, HouseholdRoomDto.class));
    }

    @Override
    public List<HouseholdRoomDto> queryList(Map<String, Object> params) {
        List<HouseholdRoomEntity> list = householdRoomDao.queryList(params);
        List<HouseholdRoomDto> result = CopyUtils.copyList(list, HouseholdRoomDto.class);
        result.forEach(this::paddingField);
        return result;
    }

    private HouseholdRoomDto paddingField(HouseholdRoomDto dto) {
        if (dto != null) {
            if (dto.getRoomId() != null) {
                dto.setVillageRoomDto(villageRoomService.selectCacheById(dto.getRoomId()));
            }
            if (dto.getHouseholdId() != null) {
                dto.setHouseholdDto(householdService.selectCacheById(dto.getHouseholdId()));
            }
        }
        return dto;
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return householdRoomDao.queryTotal(params);
    }

    @Override
    public Long save(HouseholdRoomDto dto) {
        HouseholdRoomEntity entity = CopyUtils.copyObj(dto, HouseholdRoomEntity.class);
        entity.setId(Snowflake.nextId());
        householdRoomDao.insert(entity);
        return entity.getId();
    }

    @Override
    public void updateById(HouseholdRoomDto dto) {
        HouseholdRoomEntity entity = CopyUtils.copyObj(dto, HouseholdRoomEntity.class);
        householdRoomDao.updateById(entity);
        CacheKit.invalidRedisCache(HOUSEHOLD_ROOM_CACHE_BY_ID + dto.getId());
    }

    @Override
    public void updateAllColumnById(HouseholdRoomDto dto) {

        HouseholdRoomEntity entity = CopyUtils.copyObj(dto, HouseholdRoomEntity.class);


        MyBatisPlusUtils.updateAllColumnById(entity, householdRoomDao);

        CacheKit.invalidRedisCache(HOUSEHOLD_ROOM_CACHE_BY_ID + dto.getId());
    }

    @Override
    public void deleteById(Long id) {
        householdRoomDao.deleteById(id);

        CacheKit.invalidRedisCache(HOUSEHOLD_ROOM_CACHE_BY_ID + id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            deleteById(id);
        }
    }
}
